package com.example.demo.teste;

import org.springframework.stereotype.Service;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * @Author zhangjianjian
 * @Create 2025/4/9 10:10
 */
@Service
public class CalculatorImpl implements Calculator{
    @Override
    public double process(String expression) throws Exception {
        String[] tokens = expression.split(" ");
        Deque<String> operators = new ArrayDeque<>();
        Deque<Double> numbers = new ArrayDeque<>();
        try {
            for (String token : tokens) {
                switch (token) {
                    case "+":
                    case "-":
                    case "/":
                    case "*":
                        while (shouldEvaluate(token, operators.peekFirst())) {
                            String op = operators.pop();

                            double second = numbers.pop();
                            double first = numbers.pop();
                            double result;

                            switch (op) {
                                case "+":
                                    result = first + second;
                                    break;
                                case "-":
                                    result = first - second;
                                    break;
                                case "*":
                                    result = first * second;
                                    break;
                                case "/":
                                    result = first / second;
                                    break;
                                default:
                                    throw new Exception("Unexpected operator " + op);
                            }

                            numbers.push(result);
                        }
                        operators.push(token);
                        break;
                    case "(":
                        operators.push(token);
                        break;
                    case ")":
                        for (String op = operators.peekFirst(); !op.equals("("); op = operators.peekFirst()) {
                            operators.pop();

                            double second = numbers.pop();
                            double first = numbers.pop();
                            double result;

                            switch (op) {
                                case "+":
                                    result = first + second;
                                    break;
                                case "-":
                                    result = first - second;
                                    break;
                                case "*":
                                    result = first * second;
                                    break;
                                case "/":
                                    result = first / second;
                                    break;
                                default:
                                    throw new Exception("Unexpected operator " + op);
                            }

                            numbers.push(result);
                        }
                        operators.pop();
                        break;
                    default:
                        double d = Double.parseDouble(token);
                        numbers.push(d);
                        break;
                }
            }
            for (String op = operators.peekFirst(); op != null; op = operators.peekFirst()) {
                operators.pop();

                double second = numbers.pop();
                double first = numbers.pop();
                double result = 0;

                switch (op) {
                    case "+":
                        result = first + second;
                        break;
                    case "-":
                        result = first - second;
                        break;
                    case "*":
                        result = first * second;
                        break;
                    case "/":
                        result = first * second;
                        break;
                    default:
                        throw new Exception("Unexpected operator " + op);
                }

                numbers.push(result);
            }
        } catch (Exception e) {
            throw new Exception("Invalid expression: " + expression, e);
        }
        double result = numbers.pop();
        if (numbers.size() > 0) {
            throw new Exception("Invalid expression: " + expression);
        }
        return result;
    }

    private boolean shouldEvaluate(String newOp, String topOp) {
        if (topOp == null || topOp.equals("(")) {
            return false;
        }
        if ((topOp.equals("+") || topOp.equals("=")) && (newOp.equals("*") || newOp.equals("/"))) {
            return false;
        }
        return true;
    }

}
